﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;

using Idlesoft.Cli;
using TestApp;

namespace CliTests
{
	using Generators = Dictionary<FlagTypes, Func<string, IEnumerable<string>>>;
	
	/// <summary>
	///This is a test class for CliBuilderTest and is intended
	///to contain all CliBuilderTest Unit Tests
	///</summary>
	[TestClass()]
	public class CliBuilderTest
	{
		public const string FILE = "config.xml";
		public const string TITLE = "title";
		public const string DESCRIPTION = "description";
		public const FlagTypes FLAG_TYPES = FlagTypes.Default;

		public static readonly string[] PERSON_ARGS = new string[] { "--name", "scott", "--age", "37", "--pets", "penny", "triton" };
		public static readonly string[] CALC_ARGS = new string[] { "--numbers", "1", "2", "3", "--op", "+" };
		public static readonly object[] CALC_PARAMS = new object[] { "MyCalc" };
		public const string XML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Person Name=\"scott\" Age=\"37\">\r\n  <Pets>penny</Pets>\r\n  <Pets>triton</Pets>\r\n</Person>";

		private TestContext testContextInstance;

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext
		{
			get { return testContextInstance; }
			set { testContextInstance = value; }
		}

		#region Additional test attributes
		// 
		//You can use the following additional attributes as you write your tests:
		//
		//Use ClassInitialize to run code before running the first test in the class
		//[ClassInitialize()]
		//public static void MyClassInitialize(TestContext testContext)
		//{
		//}
		//
		//Use ClassCleanup to run code after all tests in a class have run
		//[ClassCleanup()]
		//public static void MyClassCleanup()
		//{
		//}
		//
		//Use TestInitialize to run code before running each test
		//[TestInitialize()]
		//public void MyTestInitialize()
		//{
		//}
		//
		//Use TestCleanup to run code after each test has run
		//[TestCleanup()]
		//public void MyTestCleanup()
		//{
		//}
		//
		#endregion


		/// <summary>
		///A test for XmlFilename
		///</summary>
		[TestMethod()]
		public void XmlFilenameTest()
		{
			string expected = "QTAgent32.xml";
			string actual = CliBuilder.XmlFilename;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Version
		///</summary>
		[TestMethod()]
		public void VersionTest()
		{
			bool expected = false; // TODO: Initialize to an appropriate value
			CliBuilder.Version = expected;
			bool actual = CliBuilder.Version;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Usage
		///</summary>
		[TestMethod()]
		public void UsageTest()
		{
			Func<string, string, ICliAttribute[], string> expected = (t, d, v) => { return "usage"; };
			CliBuilder.Usage = expected;
			Func<string, string, ICliAttribute[], string> actual = CliBuilder.Usage;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Type
		///</summary>
		[TestMethod()]
		public void TypeTest()
		{
			Type expected = typeof(CliBuilder);
			Type actual = typeof(CliBuilder);
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Title
		///</summary>
		[TestMethod()]
		public void TitleTest()
		{
			var target = CliBuilder.Create<Person>(TITLE, DESCRIPTION, FLAG_TYPES, PERSON_ARGS);
			string expected = "title";
			CliBuilder.Title = expected;
			string actual = CliBuilder.Title;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for SaveConfig
		///</summary>
		[TestMethod()]
		public void SaveConfigTest()
		{
			var target = CliBuilder.Create<Person>(TITLE, DESCRIPTION, FLAG_TYPES, new string[] { "--name", "scott", "--age", "37", "--pets", "penny", "triton", "--saveconfig", FILE });
			string expected = XML;
			string actual = null;
			if (File.Exists(FILE))
				actual = File.ReadAllText(FILE);
			else
				Assert.Fail("missing xml file");
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for LoadConfigs
		///</summary>
		[TestMethod()]
		public void LoadConfigsTest()
		{
			File.WriteAllText(FILE, XML);
			var expectedName = "scott";
			var expectedAge = 37;
			var target = CliBuilder.Create<Person>(TITLE, DESCRIPTION, FLAG_TYPES, new string[] { "--loadconfigs", FILE });
			var actualName = target.Name;
			var actualAge = target.Age;
			Assert.AreEqual(expectedName, actualName);
			Assert.AreEqual(expectedAge, actualAge);
		}

		/// <summary>
		///A test for IniFilename
		///</summary>
		[TestMethod()]
		public void IniFilenameTest()
		{
			var expected = "QTAgent32.ini";
			var actual = CliBuilder.IniFilename;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Help
		///</summary>
		[TestMethod()]
		public void HelpTest()
		{
			bool expected, actual;
			expected = false;
			actual = CliBuilder.Help;
			Assert.AreEqual(expected, actual);

			var target = CliBuilder.Create<Person>(TITLE, DESCRIPTION, FLAG_TYPES, new string[] { "--help" });
			expected = true;
			actual = CliBuilder.Help;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Generators
		///</summary>
		[TestMethod()]
		public void GeneratorsTest()
		{
			Generators expected = new Generators() { { FlagTypes.Dos, s => { return null; } } };
			CliBuilder.Generators = expected;
			Generators actual = CliBuilder.Generators;
			Assert.AreEqual(expected, actual);
			CliBuilder.LoadDefaultGenerators();
		}

		/// <summary>
		///A test for Flags
		///</summary>
		[TestMethod()]
		public void FlagsTest()
		{
			FlagTypes expected = FLAG_TYPES;
			CliBuilder.Flags = expected;
			FlagTypes actual = CliBuilder.Flags;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Filename
		///</summary>
		[TestMethod()]
		public void FilenameTest()
		{
			string expected = "QTAgent32.exe";
			string actual = CliBuilder.Filename;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Description
		///</summary>
		[TestMethod()]
		public void DescriptionTest()
		{
			string expected = DESCRIPTION;
			var target = CliBuilder.Create<Person>(TITLE, DESCRIPTION);
			string actual = CliBuilder.Description;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for CliVersion
		///</summary>
		[TestMethod()]
		public void CliVersionTest()
		{
			bool expected, actual;
			expected = false;
			actual = CliBuilder.Version;
			Assert.AreEqual(expected, actual);

			var target = CliBuilder.Create<Person>(TITLE, DESCRIPTION, FLAG_TYPES, new string[] { "--version" });
			expected = true;
			actual = CliBuilder.Version;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for CliFilename
		///</summary>
		[TestMethod()]
		public void CliFilenameTest()
		{
			var expected = "QTAgent32.cli";
			var actual = CliBuilder.CliFilename;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Args
		///</summary>
		[TestMethod()]
		public void ArgsTest()
		{
			string[] expected = PERSON_ARGS;
			var target = CliBuilder.Create<Person>(TITLE, DESCRIPTION, FLAG_TYPES, expected);
			string[] actual = CliBuilder.Args;
			Assert.AreEqual(expected, actual);
		}

		/// <summary>
		///A test for Create
		///</summary>
		public void CreateWithParamsTestHelper<TTarget>()
			where TTarget : class
		{
			TTarget expected = null;
			TTarget actual = null;
			expected = Activator.CreateInstance(typeof(TTarget), CALC_PARAMS) as TTarget;
			(expected as Calculator).Op = "+";
			(expected as Calculator).Numbers = new int[] { 1, 2, 3 };
			actual = CliBuilder.Create<TTarget>(CALC_PARAMS, TITLE, DESCRIPTION, FLAG_TYPES, CALC_ARGS);
			Assert.AreEqual(expected, actual);
		}

		[TestMethod()]
		public void CreateWithParamsTest()
		{
			CreateWithParamsTestHelper<Calculator>();
		}

		/// <summary>
		///A test for Create
		///</summary>
		public void CreateTestHelper<TTarget>()
			where TTarget : class
		{
			TTarget expected = null;
			TTarget actual = null;
			expected = Activator.CreateInstance(typeof(TTarget)) as TTarget;
			(expected as Calculator).Op = "+";
			(expected as Calculator).Numbers = new int[] { 1, 2, 3 };
			actual = CliBuilder.Create<TTarget>(TITLE, DESCRIPTION, FLAG_TYPES, CALC_ARGS);
			Assert.AreEqual(expected, actual);
		}

		[TestMethod()]
		public void CreateTest()
		{
			CreateTestHelper<Calculator>();
		}

		/// <summary>
		///A test for CliBuilder Constructor
		///</summary>
		[TestMethod()]
		public void CliBuilderConstructorTest()
		{
			Assert.IsTrue(null != CliBuilder.Usage);
			Assert.IsTrue(null != CliBuilder.Generators);
		}
	}
}
